home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Archive / Graphics / QuickDraw GX / GX->PostScript Sample / GXToPostScript / Imaging Engine / Primitives.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  24.0 KB  |  911 lines  |  [TEXT/MPS ]

  1. /*
  2.      File:        Primitives.c
  3.  
  4.      Contains:    QuickDraw GX to PostScript conversion code.
  5.                          File contains Routines for the Geometric Primitives.
  6.                         Bitmaps and text will be in their own files
  7.  
  8.      Version:    Technology:    Quickdraw GX 1.1.x
  9.       
  10.      Copyright:    © 1991-1997 by Apple Computer, Inc., all rights reserved.
  11. */
  12.  
  13. #include <GXGraphics.h>
  14. #include "GXToPSBuildConfig.h"
  15. #include "GXToPostScript.h"
  16. #include "IOUtilities.h"
  17. #include "RDUtil.h"
  18. #include "FontHandler.h"
  19. #include "PublicPostScriptIE.h"
  20. #include "private.h"
  21. #include "PSIEResources.h"
  22. #include "GXErrors.h"
  23.  
  24.  
  25. #ifdef resumeLabel
  26.     #undef resumeLabel
  27. #endif
  28. #define resumeLabel(exception)
  29.  
  30. /***************************************
  31.  
  32.     DoExec:
  33.     Routine outputs the PostScript operator "exec"
  34.     
  35. ****************************************/
  36. OSErr DoExec(TIEGlobalsHdl hGlobals);
  37. OSErr DoExec(TIEGlobalsHdl hGlobals)
  38.     {
  39.         OSErr                 status;
  40.         unsigned char execString[] = "exec\n";
  41.         
  42.         status = PSIEBufferData(hGlobals, execString, 5, gxNoBufferOptions);
  43.         ncheck(status);
  44.         
  45.         return(status);
  46.         
  47.     }//DoExec
  48.  
  49.  
  50. /****************************************
  51.  
  52.     DoLineto:
  53.     Routine outputs a lineto for the specified point
  54.     
  55.     rdParams:                The RD parameter block.
  56.     thePoint:                The point to draw the line to.
  57.     
  58. ******************************************/
  59. OSErr    DoLineto(TRDParams *rdParams, gxPoint *thePoint);
  60. OSErr    DoLineto(TRDParams *rdParams, gxPoint *thePoint)
  61.     {
  62.         OSErr                status;
  63.         
  64.         rdParams->resIndex = kLineto;
  65.         status = RDResPrintf(rdParams, thePoint);
  66.         ncheck(status);
  67.         return(status);
  68.     
  69.     }//DoLineto
  70.     
  71. /******************************************
  72.  
  73.     DoClosepath:
  74.     Routine outputs a closepath.
  75.     
  76.     rdParams:                The RD parameter block.
  77.     
  78. *******************************************/
  79. OSErr DoClosepath(TRDParams *rdParams);
  80. OSErr DoClosepath(TRDParams *rdParams)
  81.     {
  82.         OSErr            status;
  83.         
  84.         rdParams->resIndex = kClosepath;
  85.         status = RDResPrintf(rdParams);
  86.         ncheck(status);
  87.         return(status);
  88.     
  89.     }//DoClosepath
  90.  
  91.  
  92.  
  93. /*******************************************
  94.  
  95.     DoCurveto:
  96.     Routine converts a quadratic to a cubic
  97.     and does a curveto.
  98.     
  99.     rdParams:                The RD Parameter block.
  100.     q:                            The array of quadratic points.
  101.     
  102. *********************************************/
  103. OSErr DoCurveto(TRDParams *rdParams, gxPoint q[3]);
  104. OSErr DoCurveto(TRDParams *rdParams, gxPoint q[3])
  105.     {
  106.         OSErr            status;
  107.         gxPoint        c1, c2, c3;                    // cubic control points.
  108.     
  109.         c1.x = q[0].x + FixedDivide( (q[1].x - q[0].x) << 1, ff(3) );
  110.         c2.x = q[2].x - FixedDivide( (q[2].x - q[1].x) << 1, ff(3) );
  111.  
  112.         c1.y = q[0].y + FixedDivide( (q[1].y - q[0].y) << 1, ff(3) );
  113.         c2.y = q[2].y - FixedDivide( (q[2].y - q[1].y) << 1, ff(3) );
  114.         
  115.         c3 = q[2];
  116.         
  117.         
  118.         rdParams->resIndex = kCurveto;
  119.         // Convert them to positions relative to q0.            
  120.  
  121.         status = RDResPrintf(rdParams, &c1, &c2, &c3);
  122.     
  123.         ncheck(status);
  124.         return(status);
  125.     
  126.     }//DoCurveto
  127.  
  128. //<FF>
  129. /***********************************
  130.     FullShapePrimitive:
  131.     
  132.     Output a path for a full shape in PostScript.
  133.     
  134. ************************************/
  135. OSErr _FullShapePrimitive(TIEGlobalsHdl hIEGlobals, gxShape theShape, TgeometryOptions geomOptions)
  136.     {
  137. #pragma unused(theShape, geomOptions)
  138.         OSErr                    status;
  139.         TRDParams*        pRDParams;
  140.         gxShapeFill        theFill = GXGetShapeFill(theShape);
  141.             
  142.         pRDParams = (*hIEGlobals)->pRDParams;
  143.         pRDParams->resIndex = kFullPath;
  144.     
  145.         status = RDResPrintf(pRDParams);
  146.         ncheck(status);
  147.     
  148.         return(status);    
  149.     
  150.     }//FullShapePrimitive
  151.  
  152.  
  153. /***********************************
  154.     EmptyShapePrimitive:
  155.     
  156.     Output a path for a full shape in PostScript.
  157.     
  158. ************************************/
  159. OSErr _EmptyShapePrimitive(TIEGlobalsHdl hIEGlobals, gxShape theShape, TgeometryOptions geomOptions)
  160.     {
  161. #pragma unused(theShape)
  162.         OSErr                    status;
  163.         TRDParams*        pRDParams;
  164.         
  165.         /** For clipping, output a geometry, for drawing do nothing **/
  166.         
  167.         if (geomOptions & eClipGeometry) {
  168.                 
  169.             pRDParams = (*hIEGlobals)->pRDParams;
  170.             pRDParams->resIndex = kEmptyPath;
  171.         
  172.             status = RDResPrintf(pRDParams);
  173.             ncheck(status);
  174.             
  175.         } else {
  176.         
  177.             status = noErr;
  178.             
  179.         }//end if
  180.         
  181.         return(status);    
  182.     
  183.     }//FullShapePrimitive
  184.  
  185. //<FF>
  186. /***********************************
  187.     RectanglePrimitive:
  188.     
  189.     Convert a rectangle into PostScript
  190.     All that really happens is that the 4 
  191.     parameters (top left width height) are left
  192.     on the PS operand stack.  The caller is
  193.     then responsible for dealing with it.
  194.     This allows the use of faster level-2 
  195.     rectangle procedures when possible.
  196.     
  197. *************************************/
  198. OSErr _RectanglePrimitive(TIEGlobalsHdl hIEGlobals, gxShape theShape, TgeometryOptions geomOptions)
  199.     {
  200. #pragma unused(geomOptions)
  201.         OSErr                    status;
  202.         gxRectangle        theRect;
  203.         gxPoint                topLeft;
  204.         TRDParams*        pRDParams;
  205.         long                    value;
  206.         Boolean                causesOverflow = false;
  207.         
  208.         pRDParams = (*hIEGlobals)->pRDParams;
  209.         
  210.         GXGetRectangle(theShape, &theRect);
  211.         topLeft.x = theRect.left;
  212.         topLeft.y = theRect.top;
  213.         
  214.         /*** Check to see if width or height will cause overflow ***/
  215.         
  216.         value = (long)(theRect.right >> 16) - (long)(theRect.left >> 16);
  217.         if ( (value < -32768) || (value > 32767)) {
  218.         
  219.             causesOverflow = true;
  220.             
  221.         } else {
  222.         
  223.             value = (long)(theRect.right >> 16) - (long)(theRect.left >> 16);
  224.             if ( (value < -32768) || (value > 32767) )
  225.                 causesOverflow = true;
  226.                 
  227.         }//end if
  228.         
  229.         /** Now output the parameters for the rectange operators **/
  230.             
  231.         if (!causesOverflow) {
  232.         
  233.             /** As long as there is no overflow, compute width and height here **/
  234.             gxPoint                    widthHeight;
  235.         
  236.             widthHeight.x = theRect.right - theRect.left;
  237.             widthHeight.y = theRect.bottom - theRect.top;
  238.             
  239.             pRDParams->resIndex = kRectPoints;
  240.             status = RDResPrintf(pRDParams, &topLeft, &widthHeight);
  241.             nrequire(status, failed_Output);
  242.             
  243.         } else {
  244.         
  245.             /*** relative rectangle values cause overflow, use absolute and do subtraction on printer ***/
  246.             
  247.             pRDParams->resIndex = kRectPointsAbs;
  248.             status = RDResPrintf(pRDParams, &topLeft, theRect.right, theRect.left, theRect.bottom, theRect.top);
  249.             nrequire(status, failed_Output);        
  250.         
  251.         }//end if
  252.             
  253.         
  254.         /** If we are making a procedure make the rectangle the path **/
  255.         /*** We really should check to see if we can do rectfill, etc…
  256.                     However, this requires fixing QD2Fill to check stack for true/false
  257.         *****/
  258.         if (geomOptions & eMakeProcedure) {
  259.         
  260.             pRDParams->resIndex = kRectPath;
  261.             status = RDResPrintf(pRDParams);
  262.             nrequire(status, failed_Output);
  263.         
  264.         }//end if
  265.             
  266. failed_Output:        
  267.         return(status);
  268.     
  269.     }//RectanglePrimitive
  270.  
  271.  
  272. //<FF>
  273. /***********************************
  274.     LinePrimitive:
  275.     
  276.     Convert a line into PostScript
  277.     
  278. *************************************/
  279. OSErr _LinePrimitive(TIEGlobalsHdl hIEGlobals, gxShape theShape, TgeometryOptions geomOptions)
  280.     {
  281. #pragma unused(geomOptions)
  282.         OSErr                    status;
  283.         TRDParams*        pRDParams;
  284.         gxLine                theLine;
  285.         
  286.         
  287.         GXGetLine(theShape, &theLine);
  288.         
  289.         pRDParams = (*hIEGlobals)->pRDParams;
  290.         
  291.         status = DoMoveto(pRDParams, &theLine.first);
  292.         nrequire(status, failed_Output);
  293.                 
  294.         status = DoLineto(pRDParams, &theLine.last);
  295.         ncheck(status);
  296.         
  297. failed_Output:
  298.         
  299.         return(status);
  300.     
  301.     }//LinePrimitive
  302.  
  303. //<FF>
  304. /***********************************
  305.     CurvePrimitive:
  306.     
  307.     Convert a curve into PostScript
  308.     
  309. *************************************/
  310. OSErr _CurvePrimitive(TIEGlobalsHdl hIEGlobals, gxShape theShape, TgeometryOptions geomOptions)
  311.     {
  312. #pragma unused(geomOptions)
  313.         OSErr                    status;
  314.         TRDParams*        pRDParams;
  315.         gxCurve                theCurve;        
  316.         
  317.         GXGetCurve(theShape, &theCurve);
  318.         
  319.         pRDParams = (*hIEGlobals)->pRDParams;
  320.         
  321.         status = DoMoveto(pRDParams, &theCurve.first);
  322.         nrequire(status, failed_Output);
  323.         
  324.         /** note, DoCurveto takes array of points, the curve struct parallels this.**/
  325.         
  326.         status = DoCurveto(pRDParams, (gxPoint*)&theCurve);
  327.         ncheck(status);
  328.         
  329. failed_Output:
  330.         
  331.         return(status);
  332.     
  333.     }//CurvePrimitive
  334.  
  335. //<FF>
  336. /***********************************
  337.     PointPrimitive:
  338.     
  339.     Convert a point into PostScript
  340.     
  341. *************************************/
  342. OSErr _PointPrimitive(TIEGlobalsHdl hIEGlobals, gxShape theShape, TgeometryOptions geomOptions)
  343.     {
  344. #pragma unused(geomOptions)
  345.         OSErr                    status;
  346.         TRDParams*        pRDParams;
  347.         gxPoint                thePoint;
  348.         
  349.         
  350.         GXGetPoint(theShape, &thePoint);
  351.         
  352.         pRDParams = (*hIEGlobals)->pRDParams;
  353.         pRDParams->resIndex = kPointPath;
  354.         
  355.         status = RDResPrintf(pRDParams, &thePoint);
  356.         ncheck(status);
  357.         
  358.         return(status);
  359.     
  360.     }//PointPrimitive
  361.  
  362.  
  363. //<FF>
  364. /***********************************
  365.     PolygonsPrimitive:
  366.     
  367.     Convert a multi-contoured polygon into PostScript
  368.     
  369. *************************************/
  370. OSErr _PolygonsPrimitive(TIEGlobalsHdl hIEGlobals, gxShape theShape, TgeometryOptions geomOptions)
  371.     {
  372.         OSErr                                status = noErr;
  373.         TRDParams*                    pRDParams;
  374.         Ptr                                    inPolygon;                            // We must walk through the polygons structure
  375.         gxShapeAttribute        theAttributes;
  376.         long                                i, j;
  377.         Boolean                            closeIt;                                // Is it open or closed.
  378.         long                                nContours;                            // Number of contours.
  379.         long                                nPoints;                                // Number of points in contour.
  380.         gxPoint*                        pPoint;                                    // Point to a point.
  381.         long                                size;
  382.         short                                stackLimit;                    // Usable stack limit for glyph shapes.
  383.         short                                stackUsed;                    // How much stack have we used so far?
  384.         Boolean                            wontFitOnStack;
  385.         Boolean                            procOpen;
  386.                 
  387.         /******
  388.             Usable stack space for polygons:
  389.             
  390.             take real stack limit and subtract 25 to allow other parameters
  391.             on stack involved in defining procedures, etc…
  392.         *******/
  393.         if (geomOptions & eMakeProcedure) {        // we don't care otherwise.
  394.         
  395.             stackLimit = ( (*hIEGlobals)->params.opStackLimit ) - 50;
  396.             ncheck((stackLimit < 0));
  397.             
  398.             wontFitOnStack = (GXCountShapePoints(theShape, 0) > (stackLimit / 3));        // 3 things on stack per point.
  399.             
  400.         } else {
  401.         
  402.             wontFitOnStack = false;
  403.         
  404.         }//end if
  405.         
  406.         /* If it is closedFrameFill we must close each contour */
  407.         closeIt = (GXGetShapeFill(theShape) == gxClosedFrameFill);
  408.         
  409.         /***********
  410.             Make sure we have access to the shape data structure,
  411.             and then get it
  412.         ***********/        
  413.         theAttributes = GXGetShapeAttributes(theShape);
  414.         GXSetShapeAttributes(theShape, theAttributes | gxDirectShape);
  415.         GXLockShape(theShape);
  416.         
  417.         status = GXGetGraphicsError(nil);
  418.         nrequire(status, failed_KeepDirect);
  419.         
  420.         
  421.         inPolygon = (Ptr)GXGetShapeStructure(theShape, &size);            //Get a pointer to the structure.
  422.         check(inPolygon);
  423.         
  424.         nContours = ((gxPolygons*)inPolygon)->contours;                            //Get the number of countours.
  425.  
  426.         inPolygon += sizeof(long);                                                                    //Move pointer past contours field.
  427.         
  428.         stackUsed = 0;
  429.         
  430.         /** Now output all of the contours, break up to fit on stack if necessary **/
  431.         
  432.         if (wontFitOnStack) {
  433.         
  434.             nrequire(status = DoBeginProcedure(hIEGlobals), failed_Output);    
  435.             procOpen = true;
  436.         
  437.         }//end if
  438.  
  439.         pRDParams = (*hIEGlobals)->pRDParams;
  440.         
  441.         for (i = 0; i < nContours; i++) {        // Output the contours.
  442.         
  443.             nPoints = *(long*)inPolygon;                                        // Get the number of points for this contour.
  444.             
  445.             inPolygon += sizeof(long);                                            // Move to the data.
  446.             
  447.             if (nPoints > 0) {
  448.             
  449.                 pPoint = (gxPoint*)inPolygon;                                        // Get the first point in contour.
  450.                 inPolygon += sizeof(gxPoint);                                        // Move past it.
  451.                 
  452.                 status = DoMoveto(pRDParams, pPoint);                        // Do the moveto
  453.                 nrequire(status, failed_Output);
  454.                 
  455.                 stackUsed += 3;                // Put a point on the stack and a moveto
  456.                                             
  457.                 for (j = 1; j < nPoints; j++) {                                    // Output the points for the countour.
  458.                             
  459.                     pPoint = (gxPoint*)inPolygon;                                    //        Get the next point.
  460.                     inPolygon += sizeof(gxPoint);
  461.                                     
  462.                     status = DoLineto(pRDParams, pPoint);            //        Add a line to the PS path.
  463.                     nrequire(status, failed_Output);
  464.                     
  465.                     stackUsed += 3;                // put a point on the stack plus a lineto
  466.                     
  467.                     if ((stackUsed > stackLimit) & wontFitOnStack) {
  468.                     
  469.                         nrequire(status = DoEndProcedure(hIEGlobals), failed_Output);
  470.                         nrequire(status = DoExec(hIEGlobals), failed_Output);                            // put an exec into on the stack
  471.                         nrequire(status = DoBeginProcedure(hIEGlobals), failed_Output);        // Open a new procedure
  472.                         
  473.                         stackUsed = 0;
  474.                     
  475.                     }//end if
  476.                 
  477.                 }//end for j
  478.                 
  479.                 if (closeIt) {
  480.                 
  481.                     status = DoClosepath(pRDParams);
  482.                     nrequire(status, failed_Output);
  483.                     
  484.                     ++stackUsed;                // put a closepath on the stack.
  485.                     
  486.                 }//end if
  487.                 
  488.             }//end for
  489.         
  490.         }//endo for i
  491.         
  492.         if (procOpen & wontFitOnStack) {                // left an open procedure
  493.         
  494.             nrequire(status = DoEndProcedure(hIEGlobals), failed_Output);
  495.             nrequire(status = DoExec(hIEGlobals), failed_Output);
  496.             
  497.         }//end if
  498.         
  499.         
  500. failed_Output:
  501.         /** Restore the shape to the way we got it. **/
  502.         
  503.         GXSetShapeAttributes(theShape, theAttributes);
  504.         GXUnlockShape(theShape);
  505.  
  506. failed_KeepDirect:        
  507.         
  508.         return(status);
  509.     
  510.     }//PolygonsPrimitive
  511.  
  512.  
  513.  
  514. //<FF>
  515. /***********************************
  516.     PathsPrimitive:
  517.     
  518.     Convert a multi-contoured path into PostScript
  519.     
  520. *************************************/
  521. OSErr _PathsPrimitive(TIEGlobalsHdl hIEGlobals, gxShape theShape, TgeometryOptions geomOptions)
  522.     {
  523.         OSErr                                                    status;
  524.         TRDParams*                                        pRDParams;
  525.         Ptr                                                        inPath;                            // We must walk through the Paths structure
  526.         gxShapeAttribute                            theAttributes;
  527.         long                                                    i, pointIndex;
  528.         long                                                    size;
  529.         long                                                    firstIndex, lastIndex;    // Index of first and last point ON curve.
  530.         Boolean                                                closeIt;                                // Is it open or closed.
  531.         long                                                    nContours;                            // Number of contours.
  532.         long                                                    nPoints;                                // Number of points in contour.
  533.         gxPoint*                                            pPoint;                                    // Point to a point.
  534.         gxPoint                                                firstPoint;                            // First point in the contour.
  535.         gxPoint                                                lastPoint;                            // The last point we output.
  536.         register unsigned long*                controlBitLong;                    // Pointer to control bits.
  537.         register unsigned long                cBitMask;                                // Mask for reading control bits.
  538.         unsigned long                                    lastBitMask;                        // Mask for last point in contour.
  539.         long                                                    cBitSize;                                // Number of longs for control bits.
  540.         gxPoint                                                q[3];                                        // Quadratic control points.
  541.         short                                                    qIndex;                                    // Indicates #points in curve segment so far.
  542.         Boolean                                                isOff;                                    // On the curve or off the curve.
  543.         Boolean                                                firstIsOn, lastIsOn;
  544.         short                                                    stackLimit;                            // Usable stack limit for glyph shapes.
  545.         short                                                    stackUsed;                            // How much stack have we used so far?
  546.         Boolean                                                wontFitOnStack;
  547.         Boolean                                                procOpen;
  548.         
  549.                 
  550.         /******
  551.             Usable stack space for paths:
  552.             
  553.             take real stack limit and subtract 50 to allow other parameters
  554.             on stack involved in defining procedures, etc…
  555.         *******/
  556.         if (geomOptions & eMakeProcedure) {        // we don't care otherwise.
  557.         
  558.             long numPoints;
  559.             
  560.             stackLimit = ( (*hIEGlobals)->params.opStackLimit ) - 50;
  561.             ncheck((stackLimit < 0));
  562.             
  563.             status = PSCountShapePoints(theShape, 0, &numPoints);
  564.             nrequire(status, failed_CountPoints);
  565.             
  566.             wontFitOnStack = (numPoints > (stackLimit / 3));        // 3 things on stack for each point.
  567.             
  568.         } else {
  569.         
  570.             wontFitOnStack = false;
  571.         
  572.         }//end if
  573.         
  574.         
  575.         /* If it is closedFrameFill we must close each contour */
  576.         closeIt = (GXGetShapeFill(theShape) == gxClosedFrameFill);
  577.         
  578.         /***********
  579.             Make sure we have access to the shape data structure,
  580.             and then get it
  581.         ***********/        
  582.         theAttributes = GXGetShapeAttributes(theShape);
  583.         GXSetShapeAttributes(theShape, theAttributes | gxDirectShape);
  584.         
  585.         GXLockShape(theShape);
  586.         
  587.         inPath = (Ptr)GXGetShapeStructure(theShape, &size);            //Get a pointer to the structure.
  588.         check(inPath);
  589.                 
  590.         nContours = ((gxPaths*)inPath)->contours;                            //Get the number of countours.
  591.         inPath += sizeof(long);                                                                //Move pointer past contours field.
  592.                 
  593.         status = GXGetGraphicsError(nil);
  594.         nrequire(status, failed_KeepDirect);
  595.  
  596.         stackUsed = 0;
  597.         
  598.         /** Now output all of the contours, break up to fit on stack if necessary **/
  599.         
  600.         if (wontFitOnStack) {
  601.         
  602.             nrequire(status = DoBeginProcedure(hIEGlobals), failed_Output);    
  603.             procOpen = true;
  604.         
  605.         }//end if
  606.  
  607.         pRDParams = (*hIEGlobals)->pRDParams;
  608.                 
  609.         for (i = 0; i < nContours; i++) {        // Output the contours.
  610.         
  611.             nPoints = *(long*)inPath;                                            // Get the number of points for this contour.
  612.             inPath += sizeof(long);                                                // Move to the data.
  613.                         
  614.             if (nPoints > 0) {
  615.             
  616.                 controlBitLong = (unsigned long*)inPath;            // Get to the control bits.
  617.                 
  618.                 cBitSize = (nPoints + 31) / 32;                                // Compute the size of control bits in longs.
  619.                                     
  620.                 inPath += cBitSize * sizeof(long);                        // Skip past control bits, inPath now points to first point.
  621.                 
  622.                 pPoint = (gxPoint*)inPath;                                        // Get the first point in contour, leave inPath pointing here.
  623.                 
  624.                 cBitMask = 0x80000000U;                                                // Initilize the mask for reading bits.
  625.                 
  626.                 lastBitMask = 0x80000000U >> ((nPoints-1) & 0x0000001F);                            // Mod 32
  627.                 
  628.                 
  629.                 /** Compute the first and last point on the curve **/
  630.                 
  631.                 firstIsOn =  ((*controlBitLong & cBitMask) == 0);
  632.                 lastIsOn = ( ( *(controlBitLong + cBitSize - 1) & lastBitMask) == 0);
  633.                 
  634.                 if (firstIsOn && lastIsOn) {    // They both are on.
  635.                 
  636.                     firstPoint = *pPoint;
  637.                     firstIndex = 0;
  638.                     lastPoint = *(pPoint + nPoints - 1);
  639.                     lastIndex = nPoints;
  640.                     NEXTBIT(isOff, controlBitLong, cBitMask);            // Read bit for 1st point, set up for next.
  641.                     ++pPoint;
  642.                     
  643.                 } else if (firstIsOn) {                // first was on, last was off
  644.                     
  645.                     firstPoint = *pPoint;
  646.                     firstIndex = 0;
  647.                     
  648.                     lastPoint = firstPoint;
  649.                     
  650.                     lastIndex = nPoints + 1;
  651.                     NEXTBIT(isOff, controlBitLong, cBitMask);            // Read bit for 1st point, set up for next.
  652.                     ++pPoint;
  653.                 
  654.                 
  655.                 } else if (lastIsOn) {                // last was on, first is off
  656.                 
  657.                     register gxPoint* pLastPoint = pPoint + nPoints - 1;
  658.                     
  659.                     lastPoint = *pLastPoint;
  660.                     firstPoint = lastPoint;
  661.                     lastIndex = nPoints;
  662.                     
  663.                     firstIndex = -1;
  664.                 
  665.                 } else {                                            // they were both off
  666.                 
  667.                     register gxPoint* pLastPoint = pPoint + nPoints - 1;
  668.                     
  669.                     firstIndex = -1;
  670.                     lastIndex = nPoints + 1;
  671.                     
  672.                     INTERPPOINT(lastPoint, *pPoint, *pLastPoint);
  673.                     
  674.                     firstPoint = lastPoint;
  675.                                 
  676.                 } //end if
  677.                 
  678.                 
  679.                 /*** Output the contour ****/
  680.                 
  681.                 q[0] = firstPoint;
  682.                 qIndex = 0;
  683.                 status = DoMoveto(pRDParams, &(q[0]));
  684.                 nrequire(status, failed_Output);
  685.                 
  686.                 stackUsed += 3;            // Put a point on the stack plus a moveto.
  687.     
  688.                 // Loop over all points but the first and last ON the curve.
  689.                 
  690.                 NEXTBIT(isOff, controlBitLong, cBitMask);        // Check the first point in the looping.
  691.                 pointIndex = firstIndex + 1;
  692.                 while (pointIndex < (lastIndex - 1)) {            // I know, should cache lastPointIndex-1
  693.                                     
  694.                     if (!isOff) {                                    // If the next point is on the curve:
  695.                     
  696.                         if ( qIndex == 0) {                    // If we have only q0, then do a line and start over.
  697.                     
  698.                             status = DoLineto(pRDParams, pPoint);
  699.                             nrequire(status, failed_Output);
  700.                             q[0] = *pPoint++;
  701.                             ++pointIndex;
  702.     
  703.                             NEXTBIT(isOff, controlBitLong, cBitMask);
  704.                             
  705.                             stackUsed += 3;                        // point for lineto plus the lineto
  706.                             
  707.                         } else {                                        // We must have q0 and q1, do a curve: q0, q1, q2
  708.                         
  709.                             q[2] = *pPoint++;
  710.                             status = DoCurveto(pRDParams, q);
  711.                             nrequire(status, failed_Output);
  712.                             q[0] = q[2];
  713.                             qIndex = 0;
  714.                             ++pointIndex;
  715.                             NEXTBIT(isOff, controlBitLong, cBitMask);
  716.                             
  717.                             stackUsed += 7;                    // 3 points for curveto plus the curveto
  718.                         
  719.                         }//end if
  720.                     
  721.                     } else {
  722.                     
  723.                         if (qIndex == 0) {                    // If we only have one point so far, this becomes 2nd.
  724.                         
  725.                             q[1] = *pPoint++;
  726.                             qIndex = 1;
  727.                             NEXTBIT(isOff, controlBitLong, cBitMask);
  728.                             ++pointIndex;
  729.                         
  730.                         } else {                                        // We had 2 points, interpolate to get 3rd and do a curve
  731.                         
  732.                             INTERPPOINT(q[2], q[1], *pPoint);
  733.                             
  734.                             status = DoCurveto(pRDParams, q);
  735.                             nrequire(status, failed_Output);
  736.                             qIndex = 0;
  737.                             q[0] = q[2];                    
  738.  
  739.                             stackUsed += 7;                    // 3 points for curveto plus the curveto
  740.                         
  741.                         }//end if
  742.                     
  743.                     }//end if
  744.                 
  745.                     if ((stackUsed > stackLimit) & wontFitOnStack) {
  746.                     
  747.                         nrequire(status = DoEndProcedure(hIEGlobals), failed_Output);
  748.                         nrequire(status = DoExec(hIEGlobals), failed_Output);                            // put an exec into on the stack
  749.                         nrequire(status = DoBeginProcedure(hIEGlobals), failed_Output);        // Open a new procedure
  750.                         
  751.                         stackUsed = 0;
  752.                     
  753.                     }//end if
  754.  
  755.                 }//end while
  756.                                 
  757.     
  758.                 /** Now handle the last point that is ON the curve in the contour **/
  759.                 
  760.                 if (qIndex == 0) {                // If we only had one point so far, Do a line.
  761.                                     
  762.                     status = DoLineto(pRDParams, &lastPoint);
  763.                     nrequire(status, failed_Output);        
  764.                     
  765.                     stackUsed += 3;                    // point for lineto plus the lineto
  766.                 
  767.                 } else {                                    // Else, we must have had 2 points so far, Do a curve.
  768.                 
  769.                     q[2] = lastPoint;
  770.                     status = DoCurveto(pRDParams, q);
  771.                     nrequire(status, failed_Output);
  772.                     
  773.                     stackUsed += 7;                    // 3 points for curveto plus the curveto.
  774.                 
  775.                 }//end if
  776.                 
  777.                 if (closeIt) {
  778.                 
  779.                     status = DoClosepath(pRDParams);
  780.                     nrequire(status, failed_Output);
  781.                     
  782.                     stackUsed += 1;                // put the closepath on the stack.
  783.                     
  784.                 }//end if
  785.                 
  786.                 /** Point into the next contour - inPath was pointing to first point in contour **/
  787.                 
  788.                 inPath += nPoints * sizeof(gxPoint);
  789.                                     
  790.             }//end if
  791.         
  792.         }//endo for i
  793.         
  794.         if (procOpen & wontFitOnStack) {                // left an open procedure
  795.         
  796.             nrequire(status = DoEndProcedure(hIEGlobals), failed_Output);
  797.             nrequire(status = DoExec(hIEGlobals), failed_Output);
  798.             
  799.         }//end if
  800.  
  801. failed_Output:
  802.         /** Restore things, though the shape is a copy and we really don't have to. **/
  803.         GXSetShapeAttributes(theShape, theAttributes);
  804.         GXUnlockShape(theShape);
  805.         
  806. failed_KeepDirect:        
  807.         
  808. failed_CountPoints:
  809.  
  810.         return(status);
  811.     
  812.     }//PathsPrimitive
  813.  
  814.  
  815.  
  816. //<FF>
  817. /***********************************************
  818.  
  819.     Routine:         CubicPrimitive
  820.     
  821.     Routine converts cubic synonym data into PostScript.
  822.     
  823.     We do not need to support procedure generation stack management
  824.     here since     shapes that come from patterns, dashes, etc… can never have tags
  825.     and therefore never have cubic data associated with them.
  826.     
  827. ************************************************/
  828. OSErr _CubicPrimitive(TIEGlobalsHdl hIEGlobals, gxShape theShape, TgeometryOptions geomOptions)
  829.     {
  830. #pragma unused(geomOptions)
  831.         OSErr                status;
  832.         gxTag                cubicTag;
  833.         Ptr                    cubicData;
  834.         Ptr                    inCubic, endCubic;
  835.         long                dataSize;
  836.         short                instruction;
  837.         TRDParams        *rdParams;
  838.         gxPoint            thePoints[3];
  839.         
  840.         rdParams = (*hIEGlobals)->pRDParams;
  841.         
  842.         GXGetShapeTags(theShape, gxCubicSynonymTag, 1, 1, &cubicTag);
  843.         
  844.         GXLockTag(cubicTag);
  845.         cubicData = (Ptr)GXGetTagStructure(cubicTag, &dataSize);
  846.         nrequire_action(status = GXGetGraphicsError(nil), failed_GetTag, GXUnlockTag(cubicTag););
  847.     
  848.         inCubic = cubicData;
  849.         endCubic = cubicData + dataSize;
  850.         
  851.         while(inCubic < endCubic) {
  852.         
  853.             instruction = (short)(*inCubic) & gxCubicInstructionMask;
  854.             inCubic += sizeof(short);
  855.         
  856.             switch(instruction) {
  857.             
  858.                 case gxMoveToFlag:
  859.                 
  860.                     nrequire(status = DoMoveto(rdParams, (gxPoint*)inCubic), failed_Output);
  861.                     inCubic += sizeof(gxPoint);
  862.                     
  863.                     break;
  864.                 
  865.                 case gxLineToFlag:
  866.                                     
  867.                     nrequire(status = DoLineto(rdParams, (gxPoint*)inCubic), failed_Output);
  868.                     inCubic += sizeof(gxPoint);
  869.                     
  870.                     break;
  871.                     
  872.                 case gxCurveToFlag:
  873.                 
  874.                     thePoints[0].x = ((gxPoint*)inCubic)->x;
  875.                     thePoints[0].y = ((gxPoint*)inCubic)->y;
  876.                     inCubic += sizeof(gxPoint);
  877.                     
  878.                     thePoints[1].x = ((gxPoint*)inCubic)->x;
  879.                     thePoints[1].y = ((gxPoint*)inCubic)->y;
  880.                     inCubic += sizeof(gxPoint);
  881.  
  882.                     thePoints[2].x = ((gxPoint*)inCubic)->x;
  883.                     thePoints[2].y = ((gxPoint*)inCubic)->y;
  884.                     inCubic += sizeof(gxPoint);
  885.  
  886.                     rdParams->resIndex = kCurveto;
  887.                     status = RDResPrintf(rdParams, &(thePoints[0]), &(thePoints[1]), &(thePoints[2]));
  888.  
  889.                     nrequire(status, failed_Output);
  890.  
  891.                     break;
  892.                     
  893.                 case gxClosePathFlag:
  894.                     nrequire(status = DoClosepath(rdParams), failed_Output);
  895.                     break;
  896.             
  897.             }//end switch
  898.         
  899.         }//end while
  900.                     
  901.         ncheck(status);
  902.     
  903. failed_Output:
  904.  
  905.         GXUnlockTag(cubicTag);
  906.     
  907. failed_GetTag:
  908.  
  909.         return(status);
  910.     
  911.     }//CubicPrimitive